/*
尽可能还原 Promise 中的每一个 API, 并通过注释的方式描述思路和原理.
*/

// 参考: Promise/A+ 规范: https://promisesaplus.com/

const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
    constructor(executor) {
        this.state = PENDING
        this.value = undefined
        this.reason = undefined
        this.onFulfilledCallbacks = []
        this.onRejectedCallbacks = []

        let resolve = (value) => {
            if(this.state !== PENDING) return
            this.state = FULFILLED
            this.value = value
            this.onFulfilledCallbacks.forEach(fn => fn())
            this.onFulfilledCallbacks = [] // 重置
        }
        let reject = (reason) => {
            if (this.state !== PENDING) return
            this.state = REJECTED
            this.reason = reason
            this.onRejectedCallbacks.forEach(fn => fn())
            this.onRejectedCallbacks = [] // 重置
        }

        try {
            executor(resolve, resolve)
        } catch (error) {
            reject(error)
        }
    }

    then(onFulfilled, onRejected) {
        // 兼容非函数的情况 及 不传参数的情况
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v
        onRejected = typeof onRejected === 'function' ? onRejected : r => { throw r }

        let promise2 = new MyPromise((resolve, reject) => {
            if(this.state === FULFILLED) { // 处理 FULFILLED 状态
                setTimeout(() => {
                    try {
                        let x = onFulfilled(this.value)
                        resolvePromise(promise2, x, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                }, 0)
            } else if (this.state === REJECTED) { // 处理 REJECTED 状态
                setTimeout(() => {
                    try {
                        let x = onRejected(this.reason)
                        resolvePromise(promise2, x, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                }, 0)
            } else {
                // PENDING
                // 异步时需要把回调添加到对应状态的回调队列中
                // 当异步的触发resolve或reject函数时才执行
                // setTimeout 模拟 微任务的异步效果
                this.onFulfilledCallbacks.push(() => {
                    setTimeout(() => {
                        try {
                            let x = onFulfilled(this.value)
                            resolvePromise(promise2, x, resolve, reject)
                        } catch (error) {
                            reject(error)
                        }
                    }, 0)
                })
                this.onRejectedCallbacks.push(() => {
                    setTimeout(() => {
                        try {
                            let x = onRejected(this.reason)
                            resolvePromise(promise2, x, resolve, reject)
                        } catch (error) {
                            reject(error)
                        }
                    }, 0)
                })
            }
        })

        return promise2
    }

    catch(onRejected) {
        return this.then(null, onRejected)
    }

    finally(callback) {
        return this.then(
            v => Promise.resolve(callback()).then(() => v), 
            r => Promise.resolve(callback()).then(() => { throw r }) // 如果 不用throw关键字, 会传入后面then的onFulfilled回调
        )
    }

    static resolve(value) {
        return new Promise(r => {
            r(value)
        })
    }

    static reject(value) {
        return new Promise((r, j) => {
            j(value)
        })
    }
    static all(promises) {
        return new Promise((resolve, reject) => {
            if (!Array.isArray(promises)) {
                return reject(new TypeError('is not array'))
            }
            if (!promises.length) return
            const ret = []
            const len = promises.length
            for (let i = 0; i < len; i++) {
                MyPromise.resolve(promises[i])
                    .then(val => {
                        ret[i] = val // 不能用 ret.push(val), 与传入的任务数组中的顺序不一致
                        // 最后一个结果数组传入 resolve
                        if (i === len - 1) {
                            resolve(ret)
                        }
                    })
                    .catch(reject)
            }
        })
    }
    static race(promises) {
        return new Promise((resolve, reject) => {
            if (!Array.isArray(promises)) {
                return reject(new TypeError('is not array'))
            }
            if (!promises.length) return
            promises.forEach((p) => {
                Promise.resolve(p).then(resolve, reject)
            })
        })
    }
}

function resolvePromise(promise2, x, resolve, reject) {
    if (promise2 === x) return reject(new TypeError('circle reference'))
    // try {
    //     if (x instanceof MyPromise) {
    //         x.then(resolve, reject)
    //     } else {
    //         resolve(x)
    //     }
    // } catch (error) {
    //     reject(error)
    // }

    // 完整版
    // x 为object 情况为了兼容第三方库的thenable对象 ( 对象上有then方法 )
    if (x !== null && typeof x == 'object' || typeof x == 'function') {
        let called = false
        try {
            let then = x.then
            if (typeof then === 'function') {
                then.call(x, (y) => {
                    if (called) return
                    called = true
                    resolvePromise(promise2, y, resolve, reject) // 这里递归调用 ???
                }, (r) => {
                    if (called) return
                    called = true
                    reject(r)
                })
            } else {
                if (called) return
                called = true
                resolve(x)
            }
        } catch (e) {
            if (called) return
            called = true
            reject(e)
        }
    } else {
        resolve(x)
    }
}

module.exports = MyPromise